package com.ht.callback.function.impl;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import org.springframework.stereotype.Component;

import com.ht.callback.function.Function;
import com.ht.callback.wexinaes.WeChatMessageDecryptor;
import com.ht.callback.wexinaes.XMLParse;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;

/**
 * 平台函数：微信公众号
 * @author asq
 * @createTime 2025年4月8日 15:40:26
 */
@Component
@Slf4j
public class WxOfficialFunction implements Function {

	@Override
	public String active(JSONObject appConfig, JSONObject paramUrl, String body) {
		try {
			String timestamp = paramUrl.getStr("timestamp");
			String nonce = paramUrl.getStr("nonce");
			String echostr = paramUrl.getStr("echostr");
			String signature = paramUrl.getStr("signature");
			String token = getValue(appConfig, "Token");
			
			// 1. 将token、timestamp、nonce三个参数进行字典序排序
	        String[] arr = new String[]{token, timestamp, nonce};
	        Arrays.sort(arr);
	        
	        // 2. 将三个参数字符串拼接成一个字符串
	        StringBuilder content = new StringBuilder();
	        for (String s : arr) {
	            content.append(s);
	        }
	        
	        // 3. 进行sha1加密
	        String calculatedSignature = sha1(content.toString());
	        
	        // 4. 与微信提供的signature对比
	        if (calculatedSignature != null && calculatedSignature.equals(signature)) {
	        	log.warn("恭喜，配置微信公众号回调路径时验证通过。param:{}", paramUrl.toString());
	            return echostr; // 验证成功，返回echostr
	        } else {
	        	log.warn("配置微信公众号回调路径时验证不通过。param:{}", paramUrl.toString());
	            return "Signature validation failed";
	        }
		} catch (Exception e) {
			log.error("配置微信公众号回调路径时出现异常:{}", e.getMessage(), e);
			return "error";
		}
	}

	@Override
	public String verifySign(JSONObject appConfig, JSONObject paramUrl, String body) {
		String token = getValue(appConfig, "Token");
		String encodingAesKey = getValue(appConfig, "EncodingAESKey");
		
		// 获取url参数
		String msgSignature = paramUrl.getStr("msg_signature");
		String timestamp = paramUrl.getStr("timestamp");
		String nonce = paramUrl.getStr("nonce");
		
		String desContent = null;
		try {
			// 提取密文
			Object[] encrypt = XMLParse.extract(body);
			desContent = WeChatMessageDecryptor.decryptMsg(token, encodingAesKey, msgSignature, timestamp,
					nonce, encrypt[1].toString());
		} catch (Exception e) {
			log.error("处理微信公众号回调时出现异常:{}", e.getMessage(), e);
		}
		
		return desContent;
	}

	@Override
	public String result(JSONObject paramUrl, String body) {
		return "success";
	}
	
    /**
     * SHA1加密方法
     * @param str 需要加密的字符串
     * @return 加密后的字符串
     */
    private String sha1(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] digest = md.digest(str.getBytes());
            StringBuilder hexStr = new StringBuilder();
            String shaHex;
            for (byte b : digest) {
                shaHex = Integer.toHexString(b & 0xFF);
                if (shaHex.length() < 2) {
                    hexStr.append(0);
                }
                hexStr.append(shaHex);
            }
            return hexStr.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
	
	private String getValue(JSONObject json, String name) {
	    if (json == null || StrUtil.isBlank(name)) {
	        return null;
	    }
	    
	    // 遍历 token_param
	    JSONArray tokenParams = json.getJSONArray("token_param");
	    if (tokenParams != null) {
	        for (int i = 0; i < tokenParams.size(); i++) {
	            JSONObject param = tokenParams.getJSONObject(i);
	            if (name.equals(param.getStr("name"))) {
	                return param.getStr("value");
	            }
	        }
	    }
	    
	    // 遍历 callback_decrypt
	    JSONArray callbackDecrypt = json.getJSONArray("callback_decrypt");
	    if (callbackDecrypt != null) {
	        for (int i = 0; i < callbackDecrypt.size(); i++) {
	            JSONObject param = callbackDecrypt.getJSONObject(i);
	            if (name.equals(param.getStr("name"))) {
	                return param.getStr("value");
	            }
	        }
	    }
	    
	    return null;
	}
}
